package aim;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class AIMDump {    
  /**key = the file name<br/>
   value = a DataHeader object*/
  private HashMap dataMap = new HashMap();   
  private AIMDumpIndex index = null;
  private BufferedReader fileReader;  
  
  private class DataHeader {
    public String fileName;
    public int lineFilterLen;
    public int dataStartPos;
    public int linesInFile;
    private FileReader file;
    
    public DataHeader(String fileName, int lineFilterLen, int dataStartPos, int linesInFile) {
      this.fileName = fileName;
      this.lineFilterLen = lineFilterLen;
      this.dataStartPos = dataStartPos;
      this.linesInFile = linesInFile;
    }
    
    public BufferedReader getFileInput() {
      try {
        file = new FileReader(fileName);
      } catch (FileNotFoundException ex) {
        System.err.println("Unable to open the corpus file: "+fileName);
      }
      return new BufferedReader(file);
    }
  }
  
  public AIMDump() {
    index = new AIMDumpIndex();
  }
    
  public String getMainHeaderInfo() {
    StringBuffer header = new StringBuffer();
    header.append("-------------AIM.out-------------\n");
    
    //1. Get the date and time    
    header.append("Created on: " + index.getDateTime());
    
    //2. Get the break chars
    header.append("\nCustom break characters: " + index.getBreakChars());
    
    //3. Get the stop word file absolute path    
    header.append("\nStop File path: " + index.getStopWordFilePath());
    
    //initialize variables for the corpus summary
    long corpusChars = 0;
    long corpusWords = 0;
    long corpusLines = 0;
        
    header.append("\n\n----Corpus Files----");
    long fileCount = index.getValue(Constants.NUM_INPUT_FILES_BITS);
    for(int f = 0; f < fileCount; f++) {
      //get the data header info
      String fileName = index.getInputFileName();
      int charsInFile = (int)index.getValue(Constants.FILE_CHARS_BITS);
      int wordsInFile = (int)index.getValue(Constants.FILE_WORDS_BITS);
      int linesInFile = (int)index.getValue(Constants.FILE_LINES_BITS);
      int lineFilterLen = (int)index.getValue(Constants.NUM_OFFSET_BITS);
      
      corpusChars += charsInFile;
      corpusWords += wordsInFile;
      corpusLines += linesInFile;
            
      header.append("\n\nFile name: "+fileName)
            .append("\nCharacters: "+charsInFile)
            .append("\nWords: "+wordsInFile)
            .append("\nLines: "+linesInFile);
      
      int dataBodyBits = linesInFile * lineFilterLen;
      index.skip(dataBodyBits);
    }
    
    //5. Get summary
    header.append("\n\n----Corpus Details----\n")
          .append("Characters: " + corpusChars + "\n")
          .append("Words: " + corpusWords + "\n")
          .append("Lines: " + corpusLines + "\n")
          .append("Files: " + fileCount);
    
    header.append("\n----------------------------------");
    return header.toString();
  }
    
  public void findAndDisplayOccurences(String word) {
    out("\nThe word '"+word+"' occurs as follows: ");
    
    Iterator itr = dataMap.keySet().iterator();
    while(itr.hasNext()) {
      String fileName = itr.next().toString();
      DataHeader header = (DataHeader)dataMap.get(fileName);
      index.setPosition(header.dataStartPos);
      fileReader = header.getFileInput();
      
      ArrayList output = new ArrayList();
      output.add(tab(1) + "-In file "+fileName);
      
      int linesToSkip = 0;
      boolean foundPossibleMatch = false;
      for(int lineNum = 0; lineNum < header.linesInFile; lineNum++) {
        int filter = (int)index.getValue(header.lineFilterLen);
                
        foundPossibleMatch = index.isWordOnLine(filter, lineNum, word.toLowerCase());

        if(foundPossibleMatch) {
          String line = getLineFromStream(fileReader, linesToSkip);
          int numOccurrencesInLine = isWordInLine(word.toLowerCase(), line.toLowerCase());
          for(int s = 0; s < numOccurrencesInLine; s++)
            output.add(tab(2) + "Line " + (lineNum+1) + ": " + line);
          
          linesToSkip = 0;
        }
        else
          linesToSkip++;
      }
      
      if(output.size() > 1) {
        for(int i = 0; i < output.size(); i++) 
          out(output.get(i).toString());
      }
    }
  }
  
  /** Utility method */
  private String tab(int numOfTabs) {
    final String TAB = "   ";
    String tabs = "";
    for(int t = 0; t < numOfTabs; t++)
      tabs += TAB;
    return tabs;
  }
  
  /** Returns the number of occurrences of word in line */
  private int getNumOccurrencesInLine(String line, String word) {
    int count = 0;
    for(int startIndex = line.indexOf(word); startIndex > 0; startIndex = line.indexOf(word)) {
      count++;
      int endOfWordIndex = startIndex + word.length();
      if(endOfWordIndex < line.length())
        line = line.substring(endOfWordIndex, line.length());
      else
        break;
    }
    return count;
  }
  
  private int isWordInLine(String word, String line) {
    int count = 0;
    char[] breakChars = index.getBreakCharArray();
    for(int c = 0; c < breakChars.length; c++) {
      String test = word + breakChars[c];
      if(line.indexOf(test) > 0)
        count += getNumOccurrencesInLine(line, test);
    }
    return count;
  }

  private String getLineFromStream(BufferedReader fis, int linesToSkip) {
    String line = "";    
    try {
      for(int i = 0; i < linesToSkip; i++)
        fis.readLine();
      line = fis.readLine();
    } catch (Exception e) {
      System.err.println("There was an error reading the corpus file");
    }
    return line;
  }
      
  public void initDataHeaders() {
    int fileCount = index.goToFirstDataHeader();    
    
    for(int f = 0; f < fileCount; f++) {
      //get the data header info
      String fileName = index.getInputFileName();
      index.skip(Constants.FILE_CHARS_BITS + Constants.FILE_WORDS_BITS);
      int linesInFile = (int)index.getValue(Constants.FILE_LINES_BITS);
      int lineFilterLen = (int)index.getValue(Constants.NUM_OFFSET_BITS);

      DataHeader header = new DataHeader(fileName, lineFilterLen, index.getPosition(), linesInFile);
      dataMap.put(fileName, header);
      
      int dataBodyBits = linesInFile * lineFilterLen;
      index.skip(dataBodyBits);
    }
  }  
  
  public static void main(String[] args) {
    AIMDump dump = null;
    try {
      dump = new AIMDump();      
      if(args.length == 0) {
        out(dump.getMainHeaderInfo());
      }
      else {
        dump.initDataHeaders();
        
        //output each word and a description of it's occurrences
        for(int i = 0; i < args.length; i++) {
          dump.findAndDisplayOccurences(args[i]);
        }
      }      
    }    
    catch(Throwable thr) {
      //thr.printStackTrace();
      System.err.println("There was a problem reading the index file.");
    }
  }

  private static void out(String text) {
    System.out.println(text);
  }
}
